package com.suning.sawp.member.service.impl;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Multimaps;
import com.google.gson.reflect.TypeToken;
import com.suning.sawp.constants.CacheKeyConstants;
import com.suning.sawp.exception.SawpException;
import com.suning.sawp.member.constant.LabelChannelEnum;
import com.suning.sawp.member.constant.LabelConstants;
import com.suning.sawp.member.constant.MemberConstants;
import com.suning.sawp.member.dao.LabelDao;
import com.suning.sawp.member.dto.Label;
import com.suning.sawp.member.service.LabelService;
import com.suning.sawp.member.vo.CustLabelVo;
import com.suning.sawp.member.vo.LabelVo;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.RedisCacheUtils;

/**
 * 
 * 标签服务实现<br>
 *
 * @author 14060886 祝翔龙
 */
@Service
public class LabelServiceImpl implements LabelService {

	private Logger LOGGER = LoggerFactory.getLogger(LabelServiceImpl.class);

	@Autowired
	private LabelDao labelDao;

	@Autowired
	private RedisCacheUtils redisClient;

	@Override
	public JSONObject queryLabelList(Integer pageNo) {
		List<LabelVo> labelList = new ArrayList<LabelVo>();
		Map<String, Object> params = new HashMap<String, Object>();
		Integer count = labelDao.countLabelList(params);
		if (count > 0) {
			params.put("pageNo", (pageNo - 1) * MemberConstants.PAGE_SIZE);
			params.put("pageSize", MemberConstants.PAGE_SIZE);
			labelList = labelDao.selectLabelList(params);
			for (LabelVo label : labelList) {
				if (label.getLabelType().equals(LabelConstants.LABEL_TYPE_CHOOSE)) {
					label.setSubLabelName(label.getLabelName());
					label.setLabelName(StringUtils.EMPTY);
				}
			}
		}
		JSONObject result = new JSONObject();
		result.put("labelList", labelList);
		result.put("count", count);
		return result;
	}

	@Override
	@Transactional
	public void addLabelList(LabelVo labelInfo) {
		// 参数校验
		check(labelInfo);
		// 新增选填标签
		if (labelInfo.getLabelType().equals(LabelConstants.LABEL_TYPE_CHOOSE)) {
			labelDao.saveLabel(getNewLabel(labelInfo.getLabelName(), labelInfo.getChannel(), LabelConstants.LABEL_TYPE_CHOOSE));
			// 新增必填标签
		} else {
			labelDao.saveLabel(getNewLabel(labelInfo.getLabelName(), labelInfo.getChannel(), LabelConstants.LABEL_TYPE_NEED)); // 保存父标签

			// 查询主键
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("labelName", labelInfo.getLabelName());
			LabelVo label = labelDao.selectLabelInfo(params);
			String labelId = label.getLabelId(); // 主标签id

			List<Label> insertParams = new ArrayList<Label>();
			List<LabelVo> subLabelList = labelInfo.getSubLabelList();
			for (LabelVo labelVo : subLabelList) {
				Label po = getNewLabel(labelVo.getLabelName(), labelInfo.getChannel(), LabelConstants.LABEL_TYPE_NEED);
				po.setParentId(Long.valueOf(labelId));
				insertParams.add(po);
			}
			labelDao.batchSaveLabel(insertParams);
		}
		redisClient.del(CacheKeyConstants.ALL_LABELS);
	}

	@Override
	public JSONObject queryLabelDetailById(String labelId) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("labelId", labelId);
		LabelVo label = labelDao.selectLabelInfo(params);
		if (null == label) {
			throw new SawpException("该标签不存在");
		}
		// 必填标签还需查询出子标签
		if (label.getLabelType().equals(LabelConstants.LABEL_TYPE_NEED)) {
			label.setSubLabelList(labelDao.selectSubLabelList(params));
		}
		JSONObject result = new JSONObject();
		result.put("labelInfo", label);
		return result;
	}

	@Override
	@Transactional
	public void modifyLabelList(LabelVo labelVo) {
		// 参数校验
		check(labelVo);
		// 更新标签
		labelDao.updateLabel(getModLabel(labelVo.getLabelId(), labelVo.getLabelName(), labelVo.getChannel()));
		// 更新子标签
		List<Label> insertParams = new ArrayList<Label>();
		List<LabelVo> subLabelList = labelVo.getSubLabelList();
		if (CollectionUtils.isNotEmpty(subLabelList)) {
			String parentId = labelVo.getLabelId();
			// 组装新增子标签
			for (LabelVo item : subLabelList) {
				String labelId = item.getLabelId();
				if (StringUtils.isEmpty(labelId)) {
					Label po = getNewLabel(item.getLabelName(), item.getChannel(), LabelConstants.LABEL_TYPE_NEED);
					po.setParentId(Long.valueOf(parentId));
					insertParams.add(po);
				} else {
					// 查询原标签信息
					Map<String, Object> params = new HashMap<String, Object>();
					params.put("labelId", labelId);
					LabelVo preLabel = labelDao.selectLabelInfo(params);
					Label po = getNewLabel(preLabel.getLabelId(), item.getLabelName(), preLabel.getChannel(), String.valueOf(preLabel.getParentId()), preLabel.getCreateTime());
					insertParams.add(po);
				}
			}
			// 删除原有子标签
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("parentId", parentId);
			labelDao.deleteLabelByParentId(params);
			// 新增标签
			labelDao.batchSaveLabel(insertParams);
		}
		redisClient.del(CacheKeyConstants.ALL_LABELS);
	}

	@Override
	public void deleteLabelById(String labelId) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("labelId", labelId);
		labelDao.deleteLabelById(params);
		params.clear();
		params.put("parentId", labelId);
		labelDao.deleteLabelByParentId(params);
		redisClient.del(CacheKeyConstants.ALL_LABELS);
	}

	@Override
	public List<CustLabelVo> queryLabelByCust(String custId) {
		return labelDao.selectLabelByCust(custId);
	}

	private void check(LabelVo labelInfo) {

		boolean isNew = StringUtils.isEmpty(labelInfo.getLabelId()); // labelId为空则是新增

		Map<String, Object> params = new HashMap<String, Object>();
		Integer count = labelDao.countLabelList(params); // 当前标签总数
		if (isNew && count > 19) {
			throw new SawpException("标签总数不能超过20个");
		}

		checkName(labelInfo);

		// 必填标签类型
		if (labelInfo.getLabelType().equals(LabelConstants.LABEL_TYPE_NEED)) {
			params.put("labelType", LabelConstants.LABEL_TYPE_NEED);
			count = labelDao.countLabelList(params); // 必填标签总数

			if (isNew && count > 4) {
				throw new SawpException("必填标签总数不能超过5个");
			}

			List<LabelVo> subLabelList = labelInfo.getSubLabelList();
			if (CollectionUtils.isEmpty(subLabelList)) {
				throw new SawpException("子标签不能为空");
			}

			if (subLabelList.size() > 10) {
				throw new SawpException("子标签个数不能超过10个");
			}

			for (LabelVo subLabel : subLabelList) {
				checkName(subLabel);
			}
		}
	}

	private void checkName(LabelVo labelInfo) {
		String labelId = labelInfo.getLabelId();
		boolean isNew = StringUtils.isEmpty(labelId); // labelId为空则是新增操作
		String labelName = labelInfo.getLabelName();

		if (StringUtils.isBlank(labelName)) {
			throw new SawpException("标签名称不能为空");
		}
		Map<String, Object> params = new HashMap<String, Object>();
		if (!isNew) {
			params.put("labelId", labelId);
		} else {
			params.put("labelName", labelName);
		}
		LabelVo label = labelDao.selectLabelInfo(params);

		if (isNew && null != label) {
			throw new SawpException("标签名称不能重复");
			// 更新操作剔除自己
		} else if (!isNew && null != label && !labelName.equals(label.getLabelName())) {
			params.clear();
			params.put("labelName", labelName);
			LabelVo preLabel = labelDao.selectLabelInfo(params);
			if (null != preLabel) {
				throw new SawpException("标签名称不能重复");
			}
		}
	}

	private Label getNewLabel(String labelName, String channel, String labelType) {
		Label po = new Label();
		po.setLabelName(labelName);
		po.setLabelType(labelType);
		po.setChannel(channel);
		po.setCreateTime(DateUtils.getNowLongStr());
		return po;
	}

	private Label getNewLabel(String labelId, String labelName, String channel, String parentId, String createTime) {
		Label po = new Label();
		po.setId(Long.valueOf(labelId));
		po.setLabelName(labelName);
		po.setLabelType(LabelConstants.LABEL_TYPE_NEED);
		po.setChannel(channel);
		po.setParentId(Long.valueOf(parentId));
		po.setCreateTime(createTime);
		return po;
	}

	private Label getModLabel(String labelId, String labelName, String channel) {
		Label po = new Label();
		po.setId(Long.valueOf(labelId));
		po.setLabelName(labelName);
		po.setChannel(channel);
		return po;
	}

	@Override
	public JSONObject queryAllLabel() {
		LOGGER.debug("开始查询所有标签");
		// 先从缓存获取
		String key = CacheKeyConstants.ALL_LABELS;
		String field = LabelChannelEnum.CHANNEL_SAWP.getCode();
		Type type = new TypeToken<List<Label>>() {
		}.getType();
		List<Label> list = redisClient.hget(key, field, type);
		if (list == null) {
			// 查询标签的地方没有完全写活,如果仍然有其他渠道查询，需要修改此地代码
			list = labelDao.queryAllLabel(field);
			if (CollectionUtils.isEmpty(list)) {
				return null;
			}
			redisClient.hsetWithMyExpireTime(key, field, list, CacheKeyConstants.ONE_DAY_EXPIRE_TIME);
		}

		// 一级标签
		List<Label> level1Label = getLabelByLevel(list, 1);
		List<Label> level2Label = getLabelByLevel(list, 2);

		Map<String, Collection<Label>> map = Multimaps.index(level1Label, new Function<Label, String>() {
			@Override
			public String apply(Label from) {
				return from.getLabelType();
			}
		}).asMap();
		// 可选标签
		Collection<Label> chooseLabels = map.get(MemberConstants.CHOOSED_LABEL);
		// 必填标签
		Collection<Label> requiredLabels = map.get(MemberConstants.REQUIRED_LABEL);

		Map<Long, Collection<Label>> level2Map = Multimaps.index(level2Label, new Function<Label, Long>() {
			@Override
			public Long apply(Label from) {
				return from.getParentId();
			}
		}).asMap();

		if (chooseLabels == null) {
			chooseLabels = new ArrayList<Label>(0);
		}

		if (CollectionUtils.isNotEmpty(requiredLabels)) {
			for (Label label : requiredLabels) {
				label.setSubLabels(level2Map.get(label.getId()));
			}
		} else {
			requiredLabels = new ArrayList<Label>(0);
		}

		JSONObject json = new JSONObject();
		JsonConfig config = new JsonConfig();
		config.setExcludes(new String[] { "createTime", "createUser", "labelType", "parentId" });
		json.put("chooseLabels", JSONArray.fromObject(chooseLabels, config));
		json.put("requiredLabels", JSONArray.fromObject(requiredLabels, config));
		LOGGER.debug("查询出的标签为：{}", json);
		return json;
	}

	private List<Label> getLabelByLevel(List<Label> labelList, final int level) {
		Predicate<Label> predicate = new Predicate<Label>() {
			@Override
			public boolean apply(Label input) {
				if (level == 1) {
					return input.getParentId() == null;
				}
				return input.getParentId() != null;
			}
		};
		return FluentIterable.from(labelList).filter(predicate).toList();
	}

	@Override
	public List<CustLabelVo> queryFiveLabelByCustId(Long custId) {
		return labelDao.queryFiveLabelByCustId(custId);
	}

}
